﻿using LIT.Logger.Client;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Eventing.Reader;
using System.IO;
using System.Linq;
using System.Text;

namespace LIT.Logger.ServerCheckerBL.Checkers
{
    public class WindowsEventLog
    {
        string m_fileName;
        IEventSender m_eventSender;
        IConfiguration m_config;

        public WindowsEventLog(IEventSender _eventSender, IConfiguration _config)
        {
            if (_eventSender == null)
                throw new ArgumentNullException("_eventSender");
            if (_config == null)
                throw new ArgumentNullException("_config");

            m_fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                "LIT.Logger", "LatestSent.txt");
            m_eventSender = _eventSender;
            m_config = _config;
        }

        private bool GetTimeSpan(out DateTime _dtStart, out DateTime _dtEnd)
        {
            _dtStart = DateTime.Now;
            _dtEnd = DateTime.Now;
            if (File.Exists(m_fileName))
            {
                string read = File.ReadAllText(m_fileName);
                _dtStart = DateTime.Parse(read);
                return true;
            }
            else
            {
                //First time just write the date
                WriteTime(_dtEnd);
                return false;
            }
        }

        private bool WriteTime(DateTime _date)
        {
            try
            {
                if (File.Exists(m_fileName))
                    File.Delete(m_fileName);
                string path = Path.GetDirectoryName(m_fileName);
                if (!Directory.Exists(path))
                    Directory.CreateDirectory(path);
                File.WriteAllText(m_fileName, _date.ToString());
            }
            catch (Exception ex)
            {
                m_eventSender.ReportException(new ExceptionEvent("Error writing processing information", EventType.ERROR, ex));
                return false;
            }
            return true;
        }

        
        public void SendEvents()
        {
            DateTime start;
            DateTime end;
            if (!this.GetTimeSpan(out start, out end))
                return;
            Dictionary<string, List<string>> dictEventLogs = new Dictionary<string, List<string>>();
            for (int loop = 0; loop < m_config.WindowsEventLogSourcesToSend.Count; loop++)
            {
                string source = m_config.WindowsEventLogSourcesToSend[loop];
                string[] sourceArray = source.Split(new string[] { "/", "\\" }, StringSplitOptions.RemoveEmptyEntries);
                try
                {
                    this.SendEventFromLogs(sourceArray[0], sourceArray[1], start, end);
                }
                catch (Exception ex)
                {
                    m_eventSender.ReportException(new ExceptionEvent("Error sending events from Windows Event Log",
                        EventType.ERROR, ex) { Details = "Event source: " + source });
                }
            }
            this.WriteTime(end);
            m_eventSender.ReportEvent(new Event("Event sending complete.", EventType.DEBUG, string.Format("Duration: {0}", DateTime.Now - end)));
        }

        private LIT.Logger.Client.EventType GetTypeFromLevel(byte _level)
        {
            if ( _level == 2 || _level == 1 )
                return Logger.Client.EventType.ERROR;
            else if ( _level == 3 )
                return Logger.Client.EventType.WARNING;
            else 
                return Logger.Client.EventType.INFORMATION;
        }

               
        public void SendEventFromLogs(string _eventLog, string _source, DateTime _start, DateTime _end)
        {
            StringBuilder querystring = new StringBuilder();
            querystring.AppendFormat("*[(System/Provider/@Name='{0}' or System/Provider/@Name='{1}')", _source, "Microsoft-Windows-" + _source );
            if (m_config.MinWindowsEventLogPriority == Logger.Client.EventType.WARNING.ToString())
                querystring.Append(" and (System/Level = 2 or System/Level = 3)");
            if (m_config.MinWindowsEventLogPriority == Logger.Client.EventType.ERROR.ToString())
                querystring.Append(" and System/Level = 2");
            querystring.Append("]");

            EventLogQuery query = new EventLogQuery(_eventLog, PathType.LogName, querystring.ToString());
            query.ReverseDirection = true;
            query.TolerateQueryErrors = false;
            EventLogReader reader = new EventLogReader(query);
            for (EventRecord record = reader.ReadEvent();
                record != null; record = reader.ReadEvent())
            {
                DateTime created = record.TimeCreated.GetValueOrDefault(DateTime.MinValue);
                if (created > _start && created <= _end)
                {
                    m_eventSender.ReportEvent(
                        new Logger.Client.Event("Event log entry", this.GetTypeFromLevel(record.Level.GetValueOrDefault(0)))
                        {
                            Details = string.Format("Log: {0} Source: {1}\r\nMessage: {2}", _eventLog, _source, record.FormatDescription()),
                            EventCode = record.Id,

                        });
                }
                else
                {
                    if (created <= _start)
                        break;
                }
            }
        }
    }
}
